package com.marisfrolg.gateway.filter;

import com.alibaba.fastjson.JSONObject;
import com.marisfrolg.gateway.constant.GrantType;
import com.marisfrolg.gateway.entity.OauthClientDetails;
import com.marisfrolg.gateway.service.ClientPermissionService;
import com.marisfrolg.gateway.service.OauthClientDetailsService;
import com.marisfrolg.gateway.service.TUserRoleService;
import com.marisfrolg.gateway.utils.JwtUtils;
import io.jsonwebtoken.Claims;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.util.List;

@Component
@Slf4j
public class SecurityGlobalFilter implements WebFilter {

    public static final String JWT_KEY = "jwt_key";

    @Autowired
    private OauthClientDetailsService oauthClientDetailsService;

    @Autowired
    private TUserRoleService userRoleService;

    @Autowired
    private ClientPermissionService clientPermissionService;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        String token = request.getHeaders().getFirst("Authorization");
        if (StringUtils.isEmpty(token)) {
            return resultErrorMsg(401, "登录失效", response);
        }
        // 解析JWT获取jti，以jti为key判断redis的黑名单列表是否存在，存在则拦截访问

        token = token.replace("Bearer ", "");

        Claims claims = null;
        try {
            claims = JwtUtils.verifyJwt(token, JWT_KEY);
        } catch (Exception e) {
            log.info(e.getMessage(), e);
        }
        if (claims == null) {
            return resultErrorMsg(401, "登录失效", response);
        }
        String clientId = claims.get("client_id", String.class);
        OauthClientDetails oauthClientDetails = oauthClientDetailsService.getById(clientId);
        if (oauthClientDetails == null || StringUtils.isEmpty(oauthClientDetails.getAuthorizedGrantTypes())) {
            return resultErrorMsg(401, "登录失效", response);
        }
        String authorizedGrantTypes = oauthClientDetails.getAuthorizedGrantTypes();

        String path = request.getURI().getPath();

        if (authorizedGrantTypes.contains(GrantType.client_credentials.name())) {
            boolean authorization = authorizationClient(oauthClientDetails.getClientId(), path);
            if (!authorization) {
                return resultErrorMsg(403, "没有权限", response);
            }
        } else if (authorizedGrantTypes.contains(GrantType.password.name()) || authorizedGrantTypes.contains(GrantType.authorization_code.name())) {
            String user_name = claims.get("user_name", String.class);
            if (user_name == null) {
                return resultErrorMsg(403, "没有权限", response);
            }
            boolean authorization = authorizationUser(user_name, path);
            if (!authorization) {
                return resultErrorMsg(403, "没有权限", response);
            }
        } else {
            return resultErrorMsg(401, "登录失效", response);
        }

        return chain.filter(exchange);
    }

    private boolean authorizationUser(String user_name, String path) {
        List<String> permissions = userRoleService.getPermissionsByUsername(user_name);
        return authorizationPath(path, permissions);

    }

    private boolean authorizationClient(String clientId, String path) {
        List<String> permissions = clientPermissionService.getPermissions(clientId);
        return authorizationPath(path, permissions);
    }

    private boolean authorizationPath(String path, List<String> permissions) {
        if (CollectionUtils.isEmpty(permissions)) {
            return false;
        }
        for (String permission : permissions) {
            if (path.equals(permission)) {
                return true;
            }
        }
        return false;
    }

    private Mono<Void> resultErrorMsg(Integer code, String msg, ServerHttpResponse response) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("code", code);
        jsonObject.put("message", msg);
        DataBuffer buffer = response.bufferFactory().wrap(jsonObject.toString().getBytes());
        return response.writeWith(Mono.just(buffer));
    }

}

